﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using Windows.Devices.Bluetooth;
using Windows.Devices.Bluetooth.GenericAttributeProfile;

namespace Bluetooth
{
    public partial class Form1 : Form
    {
        /// <summary>
        /// 存储检测到的设备
        /// </summary>
        public HashSet<Windows.Devices.Bluetooth.BluetoothLEDevice> DeviceList = new HashSet<Windows.Devices.Bluetooth.BluetoothLEDevice>();
        public HashSet<DeviceService> deviceServices= new HashSet<DeviceService>();
        public HashSet<GattCharacteristic> writeCharacteristic = new HashSet<GattCharacteristic>();
        public HashSet<GattCharacteristic> notifyCharacteristics = new HashSet<GattCharacteristic>();
        BleCore bleCore = new BleCore();

        public Form1()
        {
            InitializeComponent();
            CheckForIllegalCrossThreadCalls = false;
            this.Init();
        }

        // 异步线程
        public static void RunAsync(Action action)
        {
            ((Action)(delegate ()
            {
                action.Invoke();
            })).BeginInvoke(null, null);
        }

        private void Init()
        {
            this.bleCore.MessAgeLog += BleCore_MessAgeLog;
            this.bleCore.DeviceScan += BleCore_DeviceScan;
            this.bleCore.DeviceFindService += BleCore_DeviceFindService;
            this.bleCore.ReceiveNotification += BleCore_ReceiveNotification;
            this.bleCore.DeviceConnectionStatus += BleCore_DeviceConnectionStatus;
        }
        /// <summary>
        /// 日志消息
        /// </summary>
        private void BleCore_MessAgeLog(MsgType type, string message, byte[] data)
        {
            RunAsync(() =>
            {
                this.listboxMessage.Items.Add(DateTime.Now.ToString("HH:mm:ss.fff", DateTimeFormatInfo.InvariantInfo) + ": " +message);
                this.listboxMessage.SelectedIndex = this.listboxMessage.Items.Count - 1;
            });
        }

        /// <summary>
        /// 搜索蓝牙设备列表
        /// </summary>
        private void BleCore_DeviceScan(Windows.Devices.Bluetooth.BluetoothLEDevice bluetoothLEDevice)
        {
            RunAsync(() =>
            {
                byte[] _Bytes1 = BitConverter.GetBytes(bluetoothLEDevice.BluetoothAddress);
                Array.Reverse(_Bytes1);

                listviewBleDevice.Items.Add(new ListViewItem(new string[]
                {
                    bluetoothLEDevice.BluetoothAddress.ToString("X"),
                    bluetoothLEDevice.DeviceInformation.Name
                    })
                {
                    Tag = bluetoothLEDevice
                });
                this.DeviceList.Add(bluetoothLEDevice);
            });
        }

        private void BleCore_DeviceFindService(DeviceService deviceService)
        {
            deviceServices.Add(deviceService);
            listViewServer.Items.Add(new ListViewItem(deviceService.gattDeviceService.Uuid.ToString())
            {
                Tag = deviceService
            });
        }

        private void BleCore_ReceiveNotification(GattCharacteristic sender, byte[] data)
        {
            textBox_Recv.AppendText("\r\n"+sender.Uuid.ToString()+"\r\n");
            string str = System.Text.Encoding.UTF8.GetString(data);
            textBox_Recv.AppendText(str);
        }

        public void BleCore_DeviceConnectionStatus(BluetoothConnectionStatus status)
        {
            if(status == BluetoothConnectionStatus.Disconnected)
            {
                deviceServices.Clear();
                writeCharacteristic.Clear();
                notifyCharacteristics.Clear();
            }
        }

        private void connectBle()
        {
            //count = 0;
            //this.bleCore.StopBleDeviceWatcher();
            if (listviewBleDevice.SelectedItems.Count != 0)
            {
                var deviceItem = listviewBleDevice.SelectedItems[0];
                BluetoothLEDevice device = (BluetoothLEDevice)deviceItem.Tag;
                if (device != null)
                {
                    bleCore.CurrentDevice?.Dispose();
                    deviceServices.Clear();
                    notifyCharacteristics.Clear();
                    writeCharacteristic.Clear();

                    comboBoxWirteChart.Items.Clear();
                    listViewServer.Items.Clear();
                    listViewChar.Items.Clear();
                    listViewCmd.Items.Clear();

                    bleCore.StartMatching(device);
                }
                else
                {
                    MessageBox.Show("没有发现此蓝牙，请重新搜索.");
                    //this.btnServer.Enabled = false;
                }
            }
            else
            {
                MessageBox.Show("请选择连接的蓝牙.");
            }
        }


        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void btn_ble_scan_Click(object sender, EventArgs e)
        {
            if (this.btn_ble_scan.Text == "扫描蓝牙")
            {
                this.listboxMessage.Items.Clear();
                this.listviewBleDevice.Items.Clear();
                this.bleCore.StartBleDeviceWatcher();
                this.btn_ble_scan.Text = "停止扫描";
                this.bleScanCount = 5;
                timer_ble_scan.Enabled = true;
            }
            else
            {
                timer_ble_scan.Enabled = false;
                this.bleCore.StopBleDeviceWatcher();
                this.btn_ble_scan.Text = "扫描蓝牙";
            }
        }

        public int bleScanCount = 0;
        private void timer_ble_scan_Tick(object sender, EventArgs e)
        {
            this.btn_ble_scan.Text = "停止扫描(" + bleScanCount + ")";
            if (bleScanCount-- == 0)
            {
                this.bleCore.StopBleDeviceWatcher();
                this.btn_ble_scan.Text = "扫描蓝牙";
                timer_ble_scan.Enabled = false;
            }
        }

        private void btn_send_Click(object sender, EventArgs e)
        {
            if (comboBoxWirteChart.SelectedIndex < 0)
            {
                return;
            }
            byte[] decBytes = System.Text.Encoding.UTF8.GetBytes(textBox_Send.Text);
            Task.Run(async () => await bleCore.Write((GattCharacteristicItem)comboBoxWirteChart.SelectedItem, decBytes));
        }

        private void btn_ble_notify_Click(object sender, EventArgs e)
        {
            Form2 f = new Form2();
            f.ShowDialog(this);

            //bleCore.SetNotify(CurrentNotifyCharacteristic);
        }

        private void listboxBleDevice_SelectedIndexChanged(object sender, EventArgs e)
        {

        }

        private void listviewBleDevice_DoubleClick(object sender, EventArgs e)
        {
            connectBle();
        }

        private void btn_clean_send_Click(object sender, EventArgs e)
        {
            textBox_Send.Clear();
        }

        private void tabControl1_SelectedIndexChanged(object sender, EventArgs e)
        {
            if(tabControl1.SelectedTab.Text == "服务")
            {
                listViewServer.Items.Clear();
                foreach (var item in deviceServices)
                {
                    listViewServer.Items.Add(new ListViewItem(item.gattDeviceService.Uuid.ToString())
                    {
                        Tag = item
                    });
                }
            }
            else if (tabControl1.SelectedTab.Text == "发送")
            {
                comboBoxWirteChart.Items.Clear();
                
                foreach (var item in writeCharacteristic)
                {
                    comboBoxWirteChart.Items.Add(new GattCharacteristicItem(item));
                }
                if(comboBoxWirteChart.Items.Count > 0)
                {
                    comboBoxWirteChart.SelectedIndex = 0;
                }
                    
            }
            else if (tabControl1.SelectedTab.Text == "操作")
            {
                listViewCmd.Items.Clear();

                foreach (var item in writeCharacteristic)
                {
                    listViewCmd.Items.Add(new ListViewItem(new string[]
                    {
                        "Write",
                        item.Service.Uuid.ToString(),
                        item.Uuid.ToString(),
                    })
                    {
                        Tag = item
                    });
                }

                foreach (var item in notifyCharacteristics)
                {
                    listViewCmd.Items.Add(new ListViewItem(new string[]
                    {
                        "Notify",
                        item.Service.Uuid.ToString(),
                        item.Uuid.ToString(),
                    })
                    {
                        Tag = item
                    });
                }
            }
        }
        record class GattCharacteristicItem
        {
            public GattCharacteristicItem(GattCharacteristic characteristic)
            {
                Characteristic = characteristic;
            }
            public GattCharacteristic Characteristic { get; }
            public override string ToString()
            {
                return $"service:{Characteristic.Service.Uuid} char:{Characteristic.Uuid}";
            }
            public static implicit operator GattCharacteristic(GattCharacteristicItem item)
            {
                return item.Characteristic;
            }
            public static implicit operator GattCharacteristicItem(GattCharacteristic item)
            {
                return new GattCharacteristicItem(item);
            }
        }
        private void listViewServer_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (listViewServer.SelectedItems.Count == 0)
            {
                return;
            }
            listViewChar.Items.Clear();
            var serverItem = listViewServer.SelectedItems[0];
            var server = (DeviceService)serverItem.Tag;

            foreach (var item in server.gattCharacteristic)
            {
                listViewChar.Items.Add(new ListViewItem(new string[]
                {
                    item.Uuid.ToString(),
                    (item.CharacteristicProperties.HasFlag(GattCharacteristicProperties.Write)||item.CharacteristicProperties.HasFlag(GattCharacteristicProperties.WriteWithoutResponse)).ToString(),
                    item.CharacteristicProperties.HasFlag(GattCharacteristicProperties.Read).ToString(),
                    item.CharacteristicProperties.HasFlag(GattCharacteristicProperties.Notify).ToString()
                })
                {
                    Tag = item
                });
            }
        }

        private void writeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var charItem = listViewChar.SelectedItems[0];
            var characteristic = (GattCharacteristic)charItem.Tag;
            if (characteristic.CharacteristicProperties.HasFlag(GattCharacteristicProperties.WriteWithoutResponse)
                || characteristic.CharacteristicProperties.HasFlag(GattCharacteristicProperties.WriteWithoutResponse))
            {
                writeCharacteristic.Add(characteristic);
            }

        }

        private void notifyToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var charItem = listViewChar.SelectedItems[0];
            GattCharacteristic characteristic = (GattCharacteristic)charItem.Tag;
            if (characteristic.CharacteristicProperties.HasFlag(GattCharacteristicProperties.Notify) == true)
            {
                if(notifyCharacteristics.Add(characteristic) == true)
                {
                    bleCore.SetNotify(characteristic);
                }
            }
        }

        private void listviewBleDevice_SelectedIndexChanged(object sender, EventArgs e)
        {

        }

        private void button1_Click(object sender, EventArgs e)
        {

        }

        private void btn_clean_recv_Click(object sender, EventArgs e)
        {
            textBox_Recv.Clear();
        }
    }
}
